package cn.ywang.spring.framework.beans.factory.support;

import cn.ywang.spring.framework.beans.factory.config.BeanDefinition;
import cn.ywang.spring.utils.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author BeatificWang
 * @date 2019/4/22 6:50
 */
public class BeanDefinitionReader {

	private Properties properties = new Properties();

	/**
	 * 固定配置文件中的key,用来获取自动扫描的包
	 */
	public static final String SCAN_PACKAGE = "scanPackage";

	/**
	 * the resource location, to be loaded with the ResourceLoader
	 * (or ResourcePatternResolver) of this bean definition reader
	 */
	private String[] configLocations;

	/**
	 * 记录被扫描包下的所有类名，带包名
	 */
	private List<String> registryBeanClasses = new ArrayList<>();

	public BeanDefinitionReader(String... configLocations) {
		// 通过URL转换为对应的文件地址，并读取为文件流
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(
				configLocations[0].replace("classpath:", ""));
		try {
			this.properties.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		this.doScanner(this.properties.getProperty(SCAN_PACKAGE));
	}

	/**
	 * 递归扫描包下的所有类，并保存到一个registryBeanClasses
	 *
	 * @param pkgName
	 */
	private void doScanner(String pkgName) {
		// TODO:是否需要使用classloader
		URL url = this.getClass().getResource("/" + pkgName.replaceAll("\\.", "/"));
		if (url == null || url.getFile() == null) {
			return;
		}
		File classDir = new File(url.getFile());
		File[] files = classDir.listFiles();
		if (files == null) {
			return;
		}
		for (File file : files) {
			if (file.isDirectory()) {
				this.doScanner(pkgName + "." + file.getName());
			}
			else {
				this.registryBeanClasses.add(pkgName + "." + file.getName().replaceAll(".class", ""));
			}
		}
	}

	/**
	 * Load bean definitions from the specified resource location.
	 *
	 * @return bean definitions
	 */
	public List<BeanDefinition> loadBeanDefinitions() {
		List<BeanDefinition> beanDefinitions = new ArrayList<>(2);
		for (String beanClassName : this.registryBeanClasses) {
			BeanDefinition beanDefinition = this.doCreateBeanDefinition(beanClassName);
			if (null == beanDefinition) {
				continue;
			}
			beanDefinitions.add(beanDefinition);
		}
		return beanDefinitions;
	}

	/**
	 * 把类信息封装BeanDefinition
	 *
	 * @param beanClassName 类名称
	 * @return
	 */
	private BeanDefinition doCreateBeanDefinition(String beanClassName) {
		Class beanClass;
		BeanDefinition beanDefinition = null;
		try {
			beanClass = Class.forName(beanClassName);
			// 接口
			if (beanClass.isInterface()) {
				return null;
			}
			beanDefinition = new BeanDefinition();
			beanDefinition.setBeanClassName(beanClassName);
			beanDefinition.setFactoryBeanName(StringUtils.lowerFirstCase(beanClass.getCanonicalName()));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return beanDefinition;
	}

	public Properties getContextConfig() {
		return this.properties;
	}
}
